package com.ruoyi.common.utils;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.PatternMatchUtils;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;

/**
 * 安全服务工具类
 *
 * @author ruoyi
 */
public class SecurityUtils {

    /**
     * 获取当前登录用户的用户ID。
     *
     * @return 当前用户的ID
     * @throws ServiceException 如果无法获取用户信息或发生异常时抛出未授权错误
     */
    public static Long getUserId() {
        try {
            return getLoginUser().getUserId();
        } catch (Exception e) {
            throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取当前登录用户的部门ID。
     *
     * @return 当前用户的部门ID
     * @throws ServiceException 如果无法获取用户信息或发生异常时抛出未授权错误
     */
    public static Long getDeptId() {
        try {
            return getLoginUser().getDeptId();
        } catch (Exception e) {
            throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取当前登录用户的用户名（账户名）。
     *
     * @return 当前用户的用户名
     * @throws ServiceException 如果无法获取用户信息或发生异常时抛出未授权错误
     */
    public static String getUsername() {
        try {
            return getLoginUser().getUsername();
        } catch (Exception e) {
            throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取当前登录的用户对象。
     *
     * @return 登录用户对象 LoginUser
     * @throws ServiceException 如果无法获取认证信息或转换失败时抛出未授权错误
     */
    public static LoginUser getLoginUser() {
        try {
            return (LoginUser) getAuthentication().getPrincipal();
        } catch (Exception e) {
            throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取当前的安全认证信息 Authentication 对象。
     *
     * @return 当前的 Authentication 认证对象
     */
    public static Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * 使用 BCrypt 算法对给定密码进行加密处理。
     *
     * @param password 原始明文密码
     * @return 加密后的字符串
     */
    public static String encryptPassword(String password) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.encode(password);
    }

    /**
     * 比较原始密码与已加密密码是否匹配。
     *
     * @param rawPassword     明文密码
     * @param encodedPassword 已经加密过的密码字符串
     * @return 如果匹配则返回 true，否则返回 false
     */
    public static boolean matchesPassword(String rawPassword, String encodedPassword) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    /**
     * 判断指定用户是否是系统管理员（默认用户ID为1表示管理员）。
     *
     * @param userId 用户ID
     * @return 如果是管理员返回 true，否则返回 false
     */
    public static boolean isAdmin(Long userId) {
        return userId != null && 1L == userId;
    }

    /**
     * 验证当前登录用户是否具有特定权限。
     *
     * @param permission 权限标识符
     * @return 如果用户具备该权限返回 true，否则返回 false
     */
    public static boolean hasPermi(String permission) {
        return hasPermi(getLoginUser().getPermissions(), permission);
    }

    /**
     * 判断权限集合中是否包含指定权限。支持通配符匹配。
     *
     * @param authorities 权限标识符集合
     * @param permission  待验证的权限标识符
     * @return 如果权限集中存在匹配项返回 true，否则返回 false
     */
    public static boolean hasPermi(Collection<String> authorities, String permission) {
        // 过滤掉空文本，并检查是否有完全权限或模式匹配成功的情况
        return authorities.stream().filter(StringUtils::hasText)
                .anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
    }

    /**
     * 验证当前登录用户是否拥有指定角色。
     *
     * @param role 角色标识符
     * @return 如果用户具备该角色返回 true，否则返回 false
     */
    public static boolean hasRole(String role) {
        List<SysRole> roleList = getLoginUser().getUser().getRoles();
        Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
        return hasRole(roles, role);
    }

    /**
     * 判断角色集合中是否包含指定角色。支持通配符匹配。
     *
     * @param roles 角色标识符集合
     * @param role  待验证的角色标识符
     * @return 如果角色集中存在匹配项返回 true，否则返回 false
     */
    public static boolean hasRole(Collection<String> roles, String role) {
        // 过滤掉空文本，并检查是否是超级管理员或模式匹配成功的情况
        return roles.stream().filter(StringUtils::hasText)
                .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
    }

}
